import { has } from "../../underscore-master/underscore";

export var su = function() {
    function log() {
        console.log.apply(null, arguments);
    }
    //
    var root = ((typeof self == "object" && self.self === self) && (self)) ||
        ((typeof global == "object" && global.global === global) && (global)) ||
        this ||
        {};
    //
    var previousSu = root.su;
    //
    var ArrayProto = Array.prototype,
        ObjProto = Object.prototype;
    var SymbolProto = typeof Symbol !== "undefined"?Symbol.prototype:null;
    //
    var push = ArrayProto.push,
        slice = ArrayProto.slice,
        toString = ObjProto.toString,
        hasOwnProperty = ObjProto.hasOwnProperty;
    //
    var nativeIsArray = Array.isArray,
        nativeKeys = Object.keys,
        nativeCreate = Object.create;
    //
    var Ctor = function(){};
    //------------------------------
    //------------------------------
    var su = function(obj){
        if(obj instanceof su) return obj;
        if(!(this instanceof su)) return new su(obj);
        this._wrapped = obj;
    };
    //------------------------------
    if(typeof exports != "undefined" && !exports.nodeType){
        if(typeof module != "undefined" && !module.nodeType &&module.exports){
            exports = module.exports = su;
        }
        exports.su = su;
    }else{
        root.su = su;
    }
    //
    //log(root.su);
    //--------------------------------
    su.VERSION = "0.0.0";
    //--------------------------------
    var optimizeCb = function(func, context, argCount){
        if(context === void 0) return func;
        switch(argCount == null ? 3 : argCount){
            case 1: return function(value){
                return func.call(context, value);
            };
            case 3:return function(value, index, collection){
                return func.call(context, value, index, collection);
            };
            case 4:return function(accumulator, value, index, collection){
                return func.call(context, accumulator, value, index, collection);
            };
        }
        return function(){
            return func.apply(context,arguments);
        };
    };

    

    var builtinIteratee;

    //--------------------------------
    var cb = function(value, context, argCount){
        if(su.iteratee !== builtinIteratee) return su.iteratee(value, context);
        if(value == null) return su.identity;
        if(su.isFunction(value)) return optimizeCb(value, context, argCount);
        if(su.isObject(value) && !su.isArray(value)) return su.matcher(value);
        return su.property(value);
    };

    //------------------------
    su.iteratee = builtinIteratee = function(value, context){
        return cb(value, context, Infinity);
    };
    //------------------------
    var restArguments = function(func, startIndex){
        startIndex = startIndex == null ? func.length - 1 : +startIndex;
        return function(){
            var length = Math.max(arguments.length - startIndex, 0),
                rest = Array(length),
                index = 0;
            for(; index < length; index++){
                rest[index] = arguments[index + startIndex];
            }
            switch(startIndex){
                case 0: return func.call(this, rest);
                case 1: return func.call(this, arguments[0], rest);
                case 2: return func.call(this, arguments[0],arguments[1], rest);
            }
            var args = Array(startIndex + 1);
            for(index = 0; index < startIndex; index++){
                args[index] = arguments[index];
            }
            args[startIndex] = rest;
            return func.apply(this, args);
        };
    };
    //------------------------
    

    //-----------------------------------
    var baseCreate = function(prototype){
        if(!su.isObject(prototype)) return {};
        if(nativeCreate) return nativeCreate(prototype);
        Ctor.prototype = prototype;
        var result = new Ctor;
        Ctor.prototype = null;
        return result;
    };
    //--- su.property用
    var shallowProperty = function(key){
        return function(obj){
            return obj == null ? void 0 : obj[key];
        };
    };
    //--- su.property用
    var deepGet = function(obj, path){
        var length = path.length;
        for(var i = 0; i < length; i++){
            if(obj == null) return void 0;
            obj = obj[path[i]];
        }
        return length ? obj : void 0;
    };

    var has = function(obj, path){
        return obj != null && hasOwnProperty.call(obj, path);
    };

    var MAX_ARRAY_INDEX = Math.pow(2,53) - 1;
    var getLength = shallowProperty("length");
    var isArrayLike = function(collection){
        var length = getLength(collection);
        return typeof length == "number" && length >= 0 && length <= MAX_ARRAY_INDEX;
    };



    //----------------------------------------
    var hasEnumBug = !{toString: null}.propertyIsEnumerable("toString");
    var nonEnumerableProps = [
        "valueOf",
        "isPrototypeOf",
        "toString",
        "propertyIsEnumerable",
        "hasOwnProperty",
        "toLocaleString"
    ];
    //--- su.keys
    var collectNonEnumProps = function(obj, keys){
        var nonEnumIdx = nonEnumerableProps.length;
        var constructor = obj.constructor;
        var proto = su.isFunction(constructor) &&           (constructor.prototype || ObjProto);

        var prop = "constructor";
        if(has(obj, prop) && !su.contains(constructor)) keys.push(prop);

        while(nonEnumIdx--){
            prop = nonEnumerableProps[nonEnumIdx];
            if(prop in obj && obj[prop] !== proto[prop] && !su.contains(keys, prop)){
                keys.push(prop);
            }
        }
    };
    //--- su.extendOwn用  对象浅复制  keysFunc = su.keys
    var createAssigner = function(keysFunc, defaults){
        return function(obj){
            var length = arguments.length;
            if(defaults) obj = Object(obj);
            if(length < 2 || obj == null) return obj;
            for(var index = 1; index < length; index++){
                var source = arguments[index],
                keys = keysFunc(source),
                l = keys.length;
                for(var i = 0; i < l; i++){
                    var key = keys[i];
                    if(!defaults || obj[key] === void 0) obj[key] = source[key];
                }
            }
            return obj; 
        };
    };
    //--- su.findIndex  su.findLastIndex 用
    var createPredicateIndexFinder = function(dir){
        return function(array, predicate, context){
            predicate = cb(predicate, context);
            var length = getLength(array);
            var index = dir > 0 ? 0 : length - 1;
            for(; index >= 0 && index < length; index+=dir){
                if(predicate(array[index], index, array)) return index;
            }
            return -1;
        };
    };
    //--- 
    var createIndexFinder = function(dir, predicateFind, sortedIndex){
        return function(array, item, idx){
            var  i = 0, length = getLength(array);
            if(typeof idx == "number"){
                if(dir > 0){
                    i = idx >= 0 ? idx : Math.max(idx + length, i);
                }else{
                    length = idx >=0 ? Math.min(idx + 1, length) : idx + length + 1;
                }
            }else if(sortedIndex && idx && length){
                idx = sortedIndex(array, item);
                return array[idx] === item ? idx : -1;
            }
            if(item !== item){
                idx = predicateFind(slice.call(array, i, length), su.isNaN);
                return idx >= 0 ? idx + i : -1;
            }
            for(idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir){
                if(array[idx] === item) return idx;
            }
            return -1;
        };
    };

    
    //--------------------

    su.findIndex = createPredicateIndexFinder(1);

    su.findLastIndex = createPredicateIndexFinder(-1);

    su.sortedIndex = function(array, obj, iteratee, context){
        iteratee = cb(iteratee, context, 1);
        var value = iteratee(obj);
        var low = 0, high = getLength(array);
        while(low < high){
            var mid = Math.floor((low + high) / 2);
            if(iteratee(array[mid]) < value){
                low = mid + 1;
            }else{
                high = mid;
            }
        }
        return low;
    };

    su.indexOf = createIndexFinder(1, su.findIndex, su.sortedIndex);

    su.lastIndexOf = createIndexFinder(-1, su.findLastIndex);

    su.contains = su.includes = su.include = function(obj, item, fromIndex, guard){
        if(!isArrayLike(obj)) obj = su.values(obj);
        if(typeof fromIndex != "number" || guard)fromIndex = 0;
        return su.indexOf(obj,item,fromIndex) >=0;
    };
    //--------------------  basic-fns
    su.isNaN = function(obj){
        return su.isNumber() && isNaN(obj);
    };
    
    su.isArray = nativeIsArray || function(obj){
        return toString.call(obj) === "[object Array]";
    };

    su.isObject = function(obj){
        var type = typeof obj;
        return type === "function" || type === "object" && !!obj;
    };

    su.isFunction = function(obj){
        return typeof obj == "function" || false;
    };
    //--- 通过属性值比较2个对象
    su.isMatch = function(object, attrs){
        var keys = su.keys(attrs),
            length = keys.length;
        var obj = Object(object);
        for(var i = 0; i < length; i++){
            var key = keys[i];
            if(attrs[key] !== obj[key] || !(key in obj)) return false;
        }
        return true;
    };
    //--- 获取对象自身的属性名
    su.keys = function(obj){
        if(!su.isObject(obj)) return [];
        if(nativeKeys) return nativeKeys(obj);
        var keys = [];
        for(var key in obj) if(has(obj, key)) keys.push(key);
        //IE < 9
        if(hasEnumBug) collectNonEnumProps(obj, keys);
        return keys;
    };

    su.property = function(path){
        if(!su.isArray(path)){
            return shallowProperty(path);
        }
        return function(obj){
            return deepGet(obj, path);
        };
    };

    su.extendOwn = su.assign = createAssigner(su.keys);
    //--- 
    su.matcher = su.matches = function(attrs){
        attrs = su.extendOwn({}, attrs);
        return function(obj){
            return su.isMatch(obj, attrs);
        };
    };
    //--- 迭代
    su.identity = function(value){
        return value;
    };

    //------------------------
    
    var attrs = su.matcher({a:1,b:2});

    log(attrs({a:1,b:2}));
    
    
};